package com.bbva.kyfb.kyfbofo.abstracts;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.MethodUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import com.bbva.jee.arq.spring.core.log.I18nLog;
import com.bbva.jee.arq.spring.core.log.I18nLogFactory;
import com.bbva.kyfb.kyfbbofo.TLSBGeneradorId;
import com.bbva.kyfb.kyfbdaofo.interfaces.EooDao;
import com.bbva.kyfb.kyfbdaofo.interfaces.OolDao;
import com.bbva.kyfb.kyfbdaofo.interfaces.TraDao;
import com.bbva.kyfb.kyfbdaohostfo.servicios.host.acceso.AccesoSistemasHostFo;
import com.bbva.kyfb.kyfbdtofo.FicheroRequest;
import com.bbva.kyfb.kyfbdtofo.RequestDto;
import com.bbva.kyfb.kyfbdtofo.ResponseDto;
import com.bbva.kyfb.kyfbdtofo.entitys.EooDTO;
import com.bbva.kyfb.kyfbdtofo.entitys.OolDTO;
import com.bbva.kyfb.kyfbdtofo.entitys.TraDTO;
import com.bbva.kyfb.kyfbdtofo.trf.TransferenciaOutDto;
import com.bbva.kyfb.kyfbofo.interfaces.ExecuteTransactionBO;

@Service
public abstract class ExecuteTransferBOAbstract extends ExecuteBOAbstract
		implements ExecuteTransactionBO {

	@Autowired
	private EooDao eooDao;

	@Autowired
	private OolDao oolDao;
	
	@Autowired
	private TraDao traDao;
	
	@Autowired
	protected TransferenciaOutDto trfOutDto;

	@Autowired
	private ApplicationContext applicationContext;
	
	@Autowired
	protected TLSBGeneradorId tlsbGeneradorId;
	
	@Autowired
	protected TraDTO traDTO;
	
	@Autowired
	protected AccesoSistemasHostFo accesoHost;
	
	protected String desTransfer;
	
	private static final I18nLog Log = I18nLogFactory.getLogI18n(ExecuteTransferBOAbstract.class);

	@Override
	protected ResponseDto process(RequestDto aRequestDto) {
		FicheroRequest ficheroRequest = (FicheroRequest) aRequestDto;
		
		Log.info("*** Inicio recuperacion de datos Transferencia / Traspaso");

		List<EooDTO> eooDTOList = eooDao
				.selectEOOFromEOOByCodTipord(ficheroRequest.getTipoOrden());

		List<OolDTO> oolDTOList = oolDao
				.selectOODFromOOLByQnuNumitemAndTimOrden(ficheroRequest
						.getNumItem(), this.getSfoDTO().getTimFichero());
		OolDTO oolDTO = oolDTOList.get(0);

		Object object = introspection(eooDTOList, oolDTO);

		beforeTransaction(object, ficheroRequest);
		
		launchTransaction(object, ficheroRequest);
		
		afterTransaction(object);
		
		Log.info("*** Fin ejecucion de Transferencia / Traspaso");
		
		return getResponseDto();
	}
		
	protected abstract void beforeTransaction(Object object, FicheroRequest aFicheroRequest);
	
	public abstract void launchTransaction(Object object, FicheroRequest ficheroRequest);
	
	protected abstract void afterTransaction(Object object);
	
	

	protected String obtenerDatosCtaOrdenante(String ctaOrdenante) {
		String ordenante = "";
		return ordenante;
	}

	protected Object introspection(List<EooDTO> eooDTOList, OolDTO oolDTO) {

		Map<String, String> lista = new HashMap<String, String>();

		String splitPattern = oolDTO.getDesOrdenol().substring(0, 1);

		String datos = oolDTO.getDesOrdenol();
		datos = datos.substring(1, datos.length());
		String[] splitList = datos.split(splitPattern);

		for (String split : splitList) {
			String key = split.substring(0, 3);
			String value = split.substring(3, split.length());
			lista.put(key, value);
		}

		String clase = null;
		for (EooDTO eoo : eooDTOList) {
			if (eoo.getId().getCodTipord() != null) {
				clase = eoo.getId().getCodTipord();
				Log.info("*** Introspeccion --> Orden: "+eoo.getId().getCodTipord());
				break;
			}
		}

		Object instancia = factory(clase);

		String field;

		for (EooDTO item : eooDTOList) {

			int indexOf = item.getDesCampoord().indexOf(".");

			if (indexOf != -1) {

				field = item.getDesCampoord().substring(indexOf + 1,
						item.getDesCampoord().length());
			} else {
				field = item.getDesCampoord();
			}

			String key = item.getId().getCodCampoord();

			if (lista.containsKey(key)) {
				try {
					String methodName = buildmethodName(instancia.getClass(),
							field);

					MethodUtils.invokeExactMethod(instancia, methodName, lista
							.get(key).toString());

				} catch (IllegalAccessException e) {
					// e.printStackTrace();
				} catch (NoSuchMethodException e) {
					// e.printStackTrace();
				} catch (InvocationTargetException e) {
					// e.printStackTrace();
				}
			}
		}

		return instancia;
	}

	/**
	 * TODO: pasar este metodo a un bucle
	 * 
	 * @param clase
	 * @param field
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	private String buildmethodName(Class clase, String field) {
		// Forma 1
		String methodName = "set" + field.substring(0, 1).toUpperCase()
				+ field.substring(1);

		if (methodExist(clase, methodName)) {
			return methodName;
		}

		// Forma 2
		methodName = "set" + field;

		if (methodExist(clase, methodName)) {
			return methodName;
		}

		return null;
	}

	@SuppressWarnings("rawtypes")
	private boolean methodExist(Class clase, String methodName) {
		Method accessibleMethod = MethodUtils.getAccessibleMethod(clase,
				methodName, String.class);

		if (accessibleMethod != null) {
			return true;
		}

		return false;
	}

	protected Object factory(String clase) {
		if (clase == null) {
			clase = "TRF";
		}

		return applicationContext.getBean(clase);
	}

	public TraDao getTraDao() {
		return traDao;
	}

	public void setTraDao(TraDao traDao) {
		this.traDao = traDao;
	}

	public TLSBGeneradorId getTlsbGeneradorId() {
		return tlsbGeneradorId;
	}
}
